/*
 *  $Id: Log.cs 1099 2010-05-26 15:31:29Z thenn.erannor $
 *	This file is a part of Ragima CCG.
 *	(C) 2008-2009 Ragima development group.
 *
 *	Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System;
using System.Collections.Generic;
using System.IO;

using AgateLib.Geometry;
using AgateLib.InputLib;

namespace Ragima {
    public class Log: Region {
        public const int LineHeight = 16;

        private AffectIcon _icon;
        protected List<LogLine> _data;
        protected UI.Font _font;
        protected int _textRightIndent;

        public Log(Rectangle rect, UI.Font font): base(rect) {
            _icon = AffectIcon.None;
            _data = new List<LogLine>();
            _font = font;
            _textRightIndent = 0;
        }

        public AffectIcon CurrentItem {
            get { return _icon; }
            set { _icon = value; }
        }

        public int LineCapacity {
            get { return Rect.Height / LineHeight; }
        }

        public int LineCount {
            get { return _data.Count; }
        }

        public Point GetLastLinePosition() {
            int line = Math.Min(LineCount, LineCapacity) - 1;
            Point p = Rect.Location;
            p.Y += line*LineHeight;
            return p;
        }

        public int GetLineWidth(int index) {
            return _data[index].Width;
        }

        public void Add(Languages.Phrase phrase, params object[] args) {
            int width = Rect.Width - _textRightIndent;
            bool first = true;
            LogLine line = new LogLine();
            foreach (Languages.HintedPhraseText hintedText in phrase.GetHintedText(args)) {
                string s = hintedText.Text;
                int start = 0;
                while (start < s.Length) {
                    if (first) {
                        if (_icon != AffectIcon.None) line.Add(new IconLogItem(_icon));
                        first = false;
                    }
                    string lineText = _font.Wrap(s, width - line.Width, width, ref start);
                    if (!string.IsNullOrEmpty(lineText)) {
                        LogItem item;
                        if (hintedText.HasHint && hintedText.HintObject is IHintable)
                            item = new HintedTextLogItem(_font, lineText, hintedText.HintObject as IHintable);
                        else
                            item = new TextLogItem(_font, lineText);
                        line.Add(item);
                    }
                    if (start < s.Length) {
                        _data.Add(line);
                        line = new LogLine();
                    }
                }
            }
            if (line.Count > 0)
                _data.Add(line);
        }

        public void Save(string filename, bool append) {
            using (TextWriter writer = new StreamWriter(filename, append))
                foreach (LogLine line in _data) writer.WriteLine(line.ToString());
        }

        public override void Draw() {
            Point pos = GetStartPoint();
            int i = GetStartLine(), end = GetEndLine();
            while (i <= end) {
                _data[i].Draw(pos.X, pos.Y);
                pos.Y += LineHeight;
                i++;
            }
        }

        public override Hint GetHint() {
            Point pos = GetStartPoint();
            int i = GetStartLine(), end = GetEndLine();
            while (i <= end) {
                Hint hint = _data[i].GetHint(pos.X, pos.Y);
                if (hint != null) return hint;
                pos.Y += LineHeight;
                i++;
            }
            return null;
        }

        protected virtual int GetStartLine() {
            return Math.Max(_data.Count - LineCapacity, 0);
        }
        protected virtual int GetEndLine() {
            return _data.Count - 1;
        }
        protected virtual Point GetStartPoint() {
            return Rect.Location;
        }

        protected class LogLine {
            private List<LogItem> _items;
            private string _text;
            private int _width;

            public LogLine() {
                _items = new List<LogItem>();
                _text = string.Empty;
                _width = 0;
            }

            public int Width {
                get { return _width; }
            }

            public int Count {
                get { return _items.Count; }
            }

            public void Add(LogItem item) {
                _items.Add(item);
                _text += item.ToString();
                _width += item.Width;
            }

            public void Draw(int x, int y) {
                foreach (LogItem item in _items) {
                    item.Draw(x, y);
                    x += item.Width;
                }
            }

            public override string ToString() {
                return _text;
            }

            public Hint GetHint(int x, int y) {
                Point pos = Mouse.Position;
                if (pos.Y < y || pos.Y >= (y+LineHeight)) return null;
                foreach (LogItem item in _items) {
                    if (pos.X >= x && pos.X < (x+item.Width)) return item.GetHint(new Rectangle(x, y, item.Width, LineHeight));
                    x += item.Width;
                }
                return null;
            }
        }

        protected abstract class LogItem {
            public abstract int Width { get; }
            public abstract void Draw(int x, int y);
            public virtual Hint GetHint(Rectangle rect) {
                return null;
            }
        }

        protected class IconLogItem: LogItem {
            private AffectIcon _icon;

            public IconLogItem(AffectIcon icon) {
                _icon = icon;
            }

            public override int Width {
                get { return 16; }
            }

            public override void Draw(int x, int y) {
                AffectIconItem.IconSprite.Draw((int) _icon, x, y);
            }

            public override string ToString() {
                return "* ";
            }
        }

        protected class TextLogItem: LogItem {
            private UI.Font _font;
            private string _text;
            private int _width;

            public TextLogItem(UI.Font font, string text) {
                _font = font;
                _text = text;
                _width = font.GetWidth(text);
            }

            public override int Width {
                get { return _width; }
            }

            public virtual Color TextColor {
                get { return Color.Black; }
            }

            public override void Draw(int x, int y) {
                _font.Color = TextColor;
                _font.Draw(x, y, _text);
            }

            public override string ToString() {
                return _text;
            }
        }

        protected class HintedTextLogItem: TextLogItem {
            private IHintable _hintable;
            private Hint _hint;

            public HintedTextLogItem(UI.Font font, string text, IHintable hintable): base(font, text) {
                _hintable = hintable;
                _hint = null;
            }

            public override Color TextColor {
                get { return Color.Brown; }
            }

            public override Hint GetHint(Rectangle rect) {
                UpdateHint(rect);
                return _hint;
            }

            private void UpdateHint(Rectangle rect) {
                if (_hint != null && _hint.HintRect == rect) return;
                _hint = _hintable.GetHint(rect);
            }
        }
    }
}
